package com.telchina.workorder.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.telchina.common.core.domain.AjaxResult;
import com.telchina.common.domain.WoAttachment;
import com.telchina.common.enums.ApproveResultEnum;
import com.telchina.common.enums.ApproveStatusEnum;
import com.telchina.common.mapper.WoAttachmentMapper;
import com.telchina.common.service.IBaseFlowService;
import com.telchina.common.service.IWoTaskConfigService;
import com.telchina.common.utils.DateUtils;
import com.telchina.common.utils.PageUtils;
import com.telchina.common.utils.SecurityUtils;
import com.telchina.common.utils.StringUtils;
import com.telchina.workorder.domain.WoExtension;
import com.telchina.workorder.domain.WoWorkOrder;
import com.telchina.workorder.domain.vo.WoExtensionVO;
import com.telchina.workorder.mapper.WoExtensionMapper;
import com.telchina.workorder.service.IWoExtensionService;
import com.telchina.workorder.service.IWoWorkOrderService;
import com.telchina.workorder.third.config.BpmConfig;
import com.telchina.workorder.third.service.BpmProcessInstanceThirdService;
import com.telchina.workorder.third.service.BpmTaskThirdService;
import com.telchina.workorder.third.service.SystemThirdService;
import com.telchina.workorder.third.vo.ApproveResultDataVO;
import com.telchina.workorder.third.vo.TaskTodoItemRespVO;
import lombok.Synchronized;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 延期申请Service业务层处理
 *
 * @author konghao
 * @date 2023-02-21
 */
@Service
public class WoExtensionServiceImpl implements IWoExtensionService {

    public static final String BUSINESS_KEY = "extension";
    public static final String CANDIDATE_USER = "candidateUser";

    @Autowired
    private WoExtensionMapper woExtensionMapper;
    @Autowired
    private BpmConfig bpmConfig;
    @Autowired
    private SystemThirdService systemThirdService;
    @Autowired
    private BpmProcessInstanceThirdService processInstanceThirdService;
    @Autowired
    private BpmTaskThirdService taskThirdService;
    @Autowired
    private IBaseFlowService baseFlowService;
    @Autowired
    private IWoWorkOrderService woWorkOrderService;
    @Autowired
    private IWoTaskConfigService woTaskConfigService;
    @Autowired
    private WoAttachmentMapper woAttachmentMapper;


    /**
     * 查询延期申请
     *
     * @param id 延期申请ID
     * @return 延期申请
     */
    @Override
    public WoExtension selectById(String id) {
        return woExtensionMapper.selectById(id);
    }

    /**
     * 分页查询延期申请列表
     *
     * @param woExtension 延期申请
     * @return 延期申请
     */
    @Override
    public IPage<WoExtension> selectList(IPage<WoExtension> page, WoExtension woExtension) {
        return woExtensionMapper.selectWoExtensionPage(page, woExtension);
    }

    /**
     * 查询所有延期申请列表
     *
     * @param woExtension 延期申请
     * @return 延期申请
     */
    @Override
    public List<WoExtensionVO> selectListAll(WoExtension woExtension) {
        return woExtensionMapper.selectWoExtensionList(woExtension, null);
    }

    /**
     * 新增延期申请
     *
     * @param woExtension 延期申请
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult insert(WoExtension woExtension) throws Exception {
        // 判断是否存在审核中的延期申请单
        int has = woExtensionMapper.selectCount(new QueryWrapper<WoExtension>().lambda()
                .eq(WoExtension::getWorkOrderNumber, woExtension.getWorkOrderNumber())
                .eq(WoExtension::getApproveStatus, ApproveStatusEnum.IN_APPROVAL.getCode()));
        if (has > 0) {
            return AjaxResult.error("存在审批中的延期申请单，不可再次提交");
        }
        woExtension.setCreateTime(DateUtils.getNowDate());
        // 填报时间
        woExtension.setFilledTime(DateUtils.getNowDate());
        // 延期申请单号
        woExtension.setExtensionNo(getExtensionNumber());
        // 保存流程审批
        int save = woExtensionMapper.insert(woExtension);
        // 启动流程审批
        String instanceId = startFlow(woExtension);
        woExtension.setInstanceId(instanceId);
        // 审核中
        woExtension.setApproveStatus(ApproveStatusEnum.IN_APPROVAL.getCode());
        woExtensionMapper.updateById(woExtension);
        return save > 0 ? AjaxResult.success(woExtension) : AjaxResult.error();
    }

    /**
     * 启动工单流程
     *
     * @param woExtension
     * @return
     */
    private String startFlow(WoExtension woExtension) throws Exception {
        Map<String, Object> params = new HashMap<>();
        // 当前登录人
        params.put("userId", SecurityUtils.getUserId());
        // 流程实例key
        params.put("processDefinitionKey", bpmConfig.getExtensionProcessDefinitionKey());
        // 业务实例key
        params.put("businessKey", BUSINESS_KEY);
        // 绑定业务数据 start
        Map<String, Object> variablesParams = new HashMap<>();
        // 第一步审批用户
        String userIds = woTaskConfigService.getCandidateUser(bpmConfig.getExtensionProcessDefinitionKey(),
                "activity", null);
        variablesParams.put(CANDIDATE_USER, userIds);
        params.put("variables", variablesParams);
        // 绑定业务数据 end
        AjaxResult ajaxResult = processInstanceThirdService.createProcessInstance(params);
        if (!Objects.equals(ajaxResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("启动失败，提交流程异常" + ajaxResult.get(AjaxResult.MSG_TAG));
        }
        return String.valueOf(ajaxResult.get(AjaxResult.DATA_TAG));
    }

    /**
     * 修改延期申请
     *
     * @param woExtension 延期申请
     * @return 结果
     */
    @Override
    public int update(WoExtension woExtension) {
        woExtension.setUpdateTime(DateUtils.getNowDate());
        return woExtensionMapper.updateById(woExtension);
    }

    /**
     * 批量删除延期申请
     *
     * @param ids 需要删除的延期申请ID
     * @return 结果
     */
    @Override
    public int deleteByIds(String[] ids) {
        return woExtensionMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除延期申请信息
     *
     * @param id 延期申请ID
     * @return 结果
     */
    @Override
    public int deleteById(String id) {
        return woExtensionMapper.deleteById(id);
    }

    /**
     * 延期申请单待办列表
     *
     * @param extension
     * @return
     */
    @Override
    public List<WoExtensionVO> selectTodoList(WoExtension extension) {
        //  获取工单待办
        Map<String, Object> params = new HashMap<>();
        // 当前登录人
        params.put("userId", SecurityUtils.getUserId());
        // 业务实例key
        params.put("businessKey", BUSINESS_KEY);
        // 处理的范围
        params.put("assignment", "all");

        AjaxResult ajaxResult = taskThirdService.getTodoTask(params);
        // 绑定业务数据 end
        if (!Objects.equals(ajaxResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("系统异常,未查询到代办信息" + ajaxResult.get(AjaxResult.MSG_TAG));
        }
        // 数据转换
        List<TaskTodoItemRespVO> taskTodoItemRespVOList = JSON.parseArray(ajaxResult.get(AjaxResult.DATA_TAG).toString(), TaskTodoItemRespVO.class);
        // 获取流程实例的id
        List<String> instanceIds = taskTodoItemRespVOList.stream()
                .map(TaskTodoItemRespVO::getProcessInstance).map(TaskTodoItemRespVO.ProcessInstance::getId).collect(Collectors.toList());
        if (instanceIds.size() == 0) {
            // 为空时返回空集合
            return new ArrayList<WoExtensionVO>();
        }
        PageUtils.startPage();
        // 处理模糊查询
        if(StringUtils.isNotEmpty(extension.getExtensionNo())){
            extension.setExtensionNo("%" + extension.getExtensionNo() +"%");
        }
        if(StringUtils.isNotEmpty(extension.getWorkOrderNumber())){
            extension.setWorkOrderNumber("%" + extension.getWorkOrderNumber() +"%");
        }
        List<WoExtensionVO> woExtensionVOS = woExtensionMapper.selectWoExtensionList(extension, instanceIds);
        woExtensionVOS.stream().forEach(A -> {
            A.setTaskTodoItemRespVO(taskTodoItemRespVOList.stream()
                    .filter(B -> B.getProcessInstance().getId().equals(A.getInstanceId())).collect(Collectors.toList()).get(0));
        });
        return  woExtensionVOS;
    }

    /**
     * 业务单据审核处理
     *
     * @param maps
     * @return
     */
    @Override
    public AjaxResult approveExtension(Map<String, Object> maps) throws Exception {
        // 进行数据校验
        if (Objects.isNull(maps.get("extensionNo"))) {
            return AjaxResult.error("参数输入有误！");
        }
        // 进行数据校验
        if (Objects.isNull(maps.get("taskId"))) {
            return AjaxResult.error("任务id为空！");
        }
        // 进行数据校验
        if (Objects.isNull(maps.get("result"))) {
            return AjaxResult.error("审核意见不能为空！");
        }
        // 验证任务
        baseFlowService.checkUserIdDoTask(maps.get("taskId").toString());
        // 主单单号
        String extensionNo = String.valueOf(maps.get("extensionNo"));
        // 只有审核中的单据才可以审核
        WoExtension woExtension = woExtensionMapper.selectOne(new QueryWrapper<WoExtension>().lambda()
                .eq(WoExtension::getExtensionNo, extensionNo).eq(WoExtension::getApproveStatus,
                        ApproveStatusEnum.IN_APPROVAL.getCode()));
        if (Objects.isNull(woExtension)) {
            return AjaxResult.error("未找要审批的单据：【" + extensionNo + "】");
        }
        // 任务办理  开始
        // 组装参数
        Map<String, Object> approveTaskParam = new HashMap<>();
        approveTaskParam.put("userId", SecurityUtils.getUserId());
        approveTaskParam.put("deptId", systemThirdService.getLoginUseDeptId());
        approveTaskParam.put("operate", ApproveResultEnum.getValueOf(maps.get("result").toString()).getDesc());
        approveTaskParam.put("id", maps.get("taskId"));
        approveTaskParam.putAll(maps);
        approveTaskParam.put("processInstId",woExtension.getInstanceId());

        // 获取下一步节点任务属性
        AjaxResult nextUserTask = taskThirdService.getNextUserTask(approveTaskParam);
        if (!Objects.equals(nextUserTask.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("系统异常,未获取到下一步审批节点：" + nextUserTask.get(AjaxResult.MSG_TAG));
        }
        JSONObject jb = JSONObject.parseObject(nextUserTask.get(AjaxResult.DATA_TAG).toString());
        if(jb.getJSONArray("outgoingFlows").size() != 0) {
            // 获取审核角色下相关人员信息
            String userIds = woTaskConfigService.getCandidateUser(bpmConfig.getExtensionProcessDefinitionKey(),
                    jb.get("id").toString(), null);
            // 修改流程处理人参数
            maps.put("variables", new HashMap<String, Object>() {{
                put(CANDIDATE_USER, userIds);
            }}); // 下一步处理人
            maps.put("id", maps.get("taskId"));
            AjaxResult updateTaskResult = taskThirdService.updateTaskVariable(maps);
            if (!Objects.equals(updateTaskResult.get(AjaxResult.CODE_TAG), 0)) {
                throw new RuntimeException("系统异常,参数设置失败：" + updateTaskResult.get(AjaxResult.MSG_TAG));
            }
        }
        AjaxResult taskResult = new AjaxResult();
        if (maps.get("result").toString().equals(ApproveResultEnum.APPROVE.getResult())) {
            taskResult = taskThirdService.approveTask(approveTaskParam);
        } else {
            taskResult = taskThirdService.rejectTask(approveTaskParam);
        }
        if (!Objects.equals(taskResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("系统异常，任务转交失败" + taskResult.get(AjaxResult.MSG_TAG));
        }
        // 获取任务处理后的data数据  用来处理任务审批结果
        ApproveResultDataVO approveResultDataVO = JSONObject.parseObject(taskResult.get(AjaxResult.DATA_TAG).toString(),
                ApproveResultDataVO.class);
        if (approveResultDataVO.getStatus().equals(ApproveStatusEnum.COMPLETED.getCode())) { // 单据审核完成
            woExtension.setApproveTime(new Date());
            // 审核完成 -> 审核意见
            woExtension.setReplyStatus(approveResultDataVO.getResult());
            // 审核完成 -> 批复意见
            woExtension.setReplyOpinion(maps.get("result").toString());
            changeExpirationTime(woExtension, approveResultDataVO);
        }
        // 审核状态
        woExtension.setApproveStatus(approveResultDataVO.getStatus());
        woExtensionMapper.updateById(woExtension);
        return AjaxResult.success("操作成功");
    }

    /**
     * @param woExtension
     * @return
     */
    @Override
    public List<WoExtensionVO> selectListAllAndAttachment(WoExtension woExtension) {
        List<WoExtensionVO> listVO = this.selectListAll(woExtension);
        // 获取对应的附件信息
        List<String> extensionIds = listVO.stream().map(WoExtension::getId).collect(Collectors.toList());
        List<WoAttachment> woAttachmentList = Collections.emptyList();
        if(CollUtil.isNotEmpty(extensionIds)){
            woAttachmentList = woAttachmentMapper.selectList(new QueryWrapper<WoAttachment>()
                    .lambda().in(WoAttachment::getBussId, extensionIds));
        }
        List<WoAttachment> finalWoAttachmentList = woAttachmentList;
        listVO.stream().forEach(A->{
            A.setWoAttachmentList(finalWoAttachmentList.stream().filter(B->A.getId().equals(B.getBussId()))
                    .collect(Collectors.toList()));
        });
        return listVO;
    }

    /**
     * 修改工单的到期时间
     *
     * @param woExtension
     * @param approveResultDataVO
     */
    private void changeExpirationTime(WoExtension woExtension, ApproveResultDataVO approveResultDataVO) {
        WoWorkOrder woWorkOrder = woWorkOrderService.getWorkOrderByWorkOrderNumber(woExtension.getWorkOrderNumber());

        // 审核通过的情况下将工单分到期时间修改下
        // 延期申请同意后，根据批复时间更新工单表中的“到期时间”，根据到期时间与派单时间重新计算“处理期限（小时）”
        if (approveResultDataVO.getResult().equals(ApproveResultEnum.APPROVE.getResult())) {
            long hour = DateUtil.between(woExtension.getEstimatedCompletionTime(), woWorkOrder.getDispatchTime(), DateUnit.HOUR);
            woWorkOrderService.updateByWorkOrderNumber(new WoWorkOrder() {{
                setExpirationTime(woExtension.getEstimatedCompletionTime());
                setWorkOrderNumber(woExtension.getWorkOrderNumber());
                setProcessingPeriod(hour); // 处理期限
            }});
        } else {// 审核不通过的  将完成时间加上审核的时长
            Date ExpirationTime = woWorkOrder.getExpirationTime();
            // 新的到期时间
            Date newExpirationTime = DateUtils.addMilliseconds(ExpirationTime,
                    (int) (new Date().getTime() - woExtension.getFilledTime().getTime()));
            long hour = DateUtil.between(newExpirationTime, woWorkOrder.getDispatchTime(), DateUnit.HOUR);

            // 单据到期时间
            woWorkOrderService.updateByWorkOrderNumber(new WoWorkOrder() {{
                setExpirationTime(newExpirationTime);
                setWorkOrderNumber(woExtension.getWorkOrderNumber());
                setProcessingPeriod(hour); // 处理期限
            }});
        }
    }

    /**
     * 同步方法生成工单编号
     *
     * @return
     */
    @Synchronized
    private String getExtensionNumber() {
        String paramsDate = DateUtils.parseDateToStr("yyMMdd", DateUtils.getNowDate());
        // 获取当日最大单号
        WoExtension woExtension = woExtensionMapper.selectOne(new QueryWrapper<WoExtension>().select("max(extension_no) extension_no")
                .likeRight("extension_no", paramsDate));
        if (woExtension != null) {
            return String.valueOf(new BigDecimal(woExtension.getExtensionNo()).add(BigDecimal.ONE));
        } else {
            return paramsDate + "00001";
        }
    }
}
